//
//  TRSCustomSheetView.swift
//  WanAndroidLearn
//
//  Created by TRS-Mobile on 2023/11/7.
//

import Foundation
import UIKit
import SnapKit

protocol AddAssociatedProtocol: AnyObject {
    associatedtype AssociatedKeys
    
    func setAssociated<T>(value: T, associatedKey: String, policy: objc_AssociationPolicy)
    
    func getAssociated<T>(associatedKey: String) -> T?
}

extension AddAssociatedProtocol {
    func setAssociated<T>(value: T, associatedKey: String, policy: objc_AssociationPolicy) -> Void {
        let k = UnsafeRawPointer(bitPattern: associatedKey.hashValue)!
        objc_setAssociatedObject(self, k, value, policy)
    }
    
    func getAssociated<T>(associatedKey: String) -> T? {
        let k = UnsafeRawPointer(bitPattern: associatedKey.hashValue)!
        return objc_getAssociatedObject(self, k) as? T
    }
}

let SheetDuration: TimeInterval = 0.25

protocol TRSAnimationSheetable: AnyObject {
    
    /// 是否是模糊背景
    var isBlurEffectBG: Bool { set get }
    
    /// 显示为sheet
    func showInAnimationSheet()
    
    /// 点击空白消失
    func clickBlankToDisappear()
}

extension TRSAnimationSheetable {
    
    
}

extension UIView: AddAssociatedProtocol, TRSAnimationSheetable {
    enum AssociatedKeys: String {
        case window
        case isBlurEffectBG
    }
    
    var isBlurEffectBG: Bool {
        set {
            setAssociated(value: newValue, associatedKey: AssociatedKeys.isBlurEffectBG.rawValue, policy: .OBJC_ASSOCIATION_ASSIGN)
        }
        get {
            getAssociated(associatedKey: AssociatedKeys.isBlurEffectBG.rawValue) ?? false
        }
    }
    
    private var _sheetWindow: UIWindow? {
        set {
            setAssociated(value: newValue, associatedKey: AssociatedKeys.window.rawValue, policy: .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
        
        get {
            getAssociated(associatedKey: AssociatedKeys.window.rawValue)
        }
    }
    
    private var sheetWindow: UIWindow {
        guard _sheetWindow == nil else { return _sheetWindow! }
        let window = UIWindow(frame: UIScreen.main.bounds)
        window.windowLevel = .alert
        if isBlurEffectBG {
            let blurEffect = UIBlurEffect(style: .light)
            let blurView = UIVisualEffectView(effect: blurEffect)
            blurView.backgroundColor = .black.withAlphaComponent(0.3)
            window.addSubview(blurView)
            blurView.snp.makeConstraints { make in
                make.edges.equalToSuperview()
            }
        }
        let bt = UIButton(type: .custom)
        bt.addTarget(self, action: #selector(tapToDisapear), for: .touchUpInside)
        window.addSubview(bt)
        bt.snp.makeConstraints { make in
            make.edges.equalToSuperview()
        }
        _sheetWindow = window
        return window
    }
    
    @objc func tapToDisapear() -> Void {
        clickBlankToDisappear()
    }
    
    /// 显示为sheet
    func showInAnimationSheet() {
        UIView.animate(withDuration: 0.1) {
            self.sheetWindow.isHidden = false
            if !self.isBlurEffectBG {
                self.sheetWindow.backgroundColor = .black.withAlphaComponent(0.3)
            }
        } completion: { _ in
            self.sheetWindow.addSubview(self)
            let h = self.height
            self.frame = CGRectMake(0, self.sheetWindow.frame.maxY, self.sheetWindow.width, h)
            UIView.animate(withDuration: SheetDuration,
                           delay: 0, options: .curveEaseIn) {
                self.frame = CGRectMake(0, self.sheetWindow.frame.maxY - h, self.sheetWindow.width, h)
            }
        }
    }
    
    /// 点击空白消失
    func clickBlankToDisappear() {
        let h = self.height
        UIView.animate(withDuration: SheetDuration, 
                       delay: 0,
                       options: .curveEaseOut) {
            self.frame = CGRectMake(0, self.sheetWindow.frame.maxY, self.sheetWindow.width, h)
        } completion: { _ in
            UIView.animate(withDuration: 0.1) {
                self.sheetWindow.isHidden = true
            } completion: { _ in
                self.sheetWindow.backgroundColor = .clear
            }
        }
    }
}
